package com.wfh.picture.manager.upload;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.RandomUtil;
import com.luciad.imageio.webp.WebPWriteParam;
import com.wfh.picture.exception.BusinessException;
import com.wfh.picture.exception.ErrorCode;
import com.wfh.picture.manager.ObsManager;
import com.wfh.picture.model.dto.file.UploadPictureResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;

/**
 * @Author FengHuan Wang
 * @Date 2025/5/9 14:20
 * @Version 1.0
 */
@Slf4j
public abstract class BasePictureUploadTemplate {

    @Resource
    private ObsManager obsManager;

    /**
     * 上传图片
     * @param inputSource
     * @param uploadPrefix
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public UploadPictureResult uploadPicture(Object inputSource, String uploadPrefix){
        // 校验图片
        validPicture(inputSource);
        // 图片上传地址
        String filename = getOriginFilename(inputSource);
        String uuid = RandomUtil.randomString(16);
        // 自己拼接文件上传路径
        String uploadFileName = String.format("%s_%s.%s", DateUtil.formatDate(new Date()),
                uuid, "webp");
        String uploadPath = String.format("%s/%s/%s", uploadPrefix, "origin", uploadFileName);
        // 上传文件
        File file = null;
        try {
            // 获取文件到服务器
            file = File.createTempFile(uploadPath, null);
            // 处理文件来源
            processFile(inputSource, file);
            // 将图片转化为webp文件
            encode(Files.newInputStream(Path.of(file.getPath())), file);
            // 上传原图
            String originUploadUrl = obsManager.upload(file, uploadPath);
            // 对图片处理成缩略图
            String inputPath = file.getPath();
            // 目标宽高
            int height = 128;
            int width = 128;
            BufferedImage read = ImageIO.read(file);
            int height1 = read.getHeight();
            int width1 = read.getWidth();
            // 只有原图比目标宽高打，就进行压缩
            if (height1 > height || width1 > width){
                try {
                    // 原始图片路径 inputPath
                    BufferedImage originalImage = ImageIO.read(new File(inputPath));
                    // 创建缩略图（Java 自带方法）
                    Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                    BufferedImage thumbnailImage = new BufferedImage(width, height, originalImage.getType());
                    Graphics2D g2d = thumbnailImage.createGraphics();
                    g2d.drawImage(scaledImage, 0, 0, null);
                    g2d.dispose();
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(originalImage, "webp", baos);
                    byte[] byteArray = baos.toByteArray();
                    // 使用你之前的 encode 方法写入 WebP 文件
                    this.encode(new ByteArrayInputStream(byteArray), file);
                } catch (IOException e) {
                    log.error("缩略图处理失败：{}", e.getMessage());
                    throw new BusinessException(ErrorCode.SYSTEM_ERROR, "缩略图处理失败");
                }
            }
            uploadPath = String.format("%s/%s/%s", uploadPrefix, "zip", uploadFileName);
            // 上传缩略图
            String zipUploadUrl = obsManager.upload(file, uploadPath);
            // 返回结果
            return buildResult(read, file, originUploadUrl, filename, zipUploadUrl);
        } catch (IOException e) {
            log.error("文件{}上传失败：{}", uploadPath, e.getMessage());
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "上传文件失败");
        }finally {
            // 临时文件清理
            delTempFile(file, uploadPath);
        }
    }

    /**
     * 构建返回结果
     * @param file
     * @param zipUploadUrl
     * @param filename
     * @return
     * @throws IOException
     */
    private static UploadPictureResult buildResult(BufferedImage image,  File file, String originUploadUrl, String filename, String zipUploadUrl) throws IOException {
        if (!file.exists()){
            log.error("文件不存在");
        }
        int width = image.getWidth();
        int height = image.getHeight();
        //获取图片的主色调
        Color mainColor = getMainColor(image);
        int green = mainColor.getGreen();
        int red = mainColor.getRed();
        int blue = mainColor.getBlue();
        // 将RGB值转换为十六进制字符串
        String hexColor = String.format("#%02X%02X%02X", red, green, blue);
        double ratio = (double) width /(double) height;
        // 封装返回结果
        UploadPictureResult uploadPictureResult = new UploadPictureResult();
        uploadPictureResult.setUrl(originUploadUrl);
        uploadPictureResult.setPicName(FileUtil.mainName(filename));
        uploadPictureResult.setPicSize(FileUtil.size(file));
        uploadPictureResult.setPicWidth(width);
        uploadPictureResult.setPicHeight(height);
        uploadPictureResult.setPicScale(ratio);
        uploadPictureResult.setThumbnailUrl(zipUploadUrl);
        uploadPictureResult.setPicColor(hexColor);
        uploadPictureResult.setPicFormat(FileNameUtil.extName(filename));
        // 返回
        return uploadPictureResult;
    }

    /**
     * 处理文件
     *
     * @param inputSource
     * @param file
     */
    protected abstract void processFile(Object inputSource, File file) throws IOException;

    /**
     * 获取文件名称
     * @param inputSource
     * @return
     */
    protected abstract String getOriginFilename(Object inputSource);

    /**
     * 校验输入源
     * @param inputSource
     */
    protected abstract void validPicture(Object inputSource);

    /**
     * 临时文件清理
     * @param file
     * @param uploadPath
     */
    private static void delTempFile(File file, String uploadPath) {
        if (file != null){
            // 删除临时文件
            boolean delete = file.delete();
            if (!delete){
                log.error("删除临时文件{}失败", uploadPath);
            }
        }
    }

    /**
     * 编码为webp文件
     * @param in
     * @param file
     * @throws IOException
     */
    public void encode(InputStream in, File file) throws IOException {
        BufferedImage image = ImageIO.read(in);
        if (image == null) {
            throw new IOException("无法读取图像文件");
        }

        Iterator<ImageWriter> writers = ImageIO.getImageWritersByMIMEType("image/webp");
        if (!writers.hasNext()) {
            throw new IOException("没有找到支持 WebP 的 ImageWriter，请检查依赖是否正确加载");
        }

        ImageWriter writer = writers.next();
        WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());

        // 设置为显式压缩模式
        writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

        // 打印所有可用的压缩类型以供调试
        String[] compressionTypes = writeParam.getCompressionTypes();
        System.out.println("可用的压缩类型: " + Arrays.toString(compressionTypes));

        // 如果需要无损压缩
        boolean losslessSupported = true;
        for (int i = 0; i < compressionTypes.length; i++) {
            if ("Lossless".equalsIgnoreCase(compressionTypes[i])) {
                writeParam.setCompressionType(compressionTypes[i]);
                losslessSupported = false;
                break;
            }
        }

        if (!losslessSupported) {
            // 如果不支持无损压缩，或者你想使用有损压缩
            writeParam.setCompressionQuality(0.75f); // 示例压缩质量
        }

        try (ImageOutputStream output = new FileImageOutputStream(file)) {
            writer.setOutput(output);
            writer.write(null, new IIOImage(image, null, null), writeParam);
        } finally {
            writer.dispose(); // 确保释放资源
        }
    }

    /**
     * 获取图片的主色调
     * @param image
     * @return
     */
    public static Color getMainColor(BufferedImage image) {
        Map<Color, Integer> colorCountMap = new HashMap<>();
        int width = image.getWidth();
        int height = image.getHeight();

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                Color color = new Color(image.getRGB(x, y));
                colorCountMap.put(color, colorCountMap.getOrDefault(color, 0) + 1);
            }
        }

        Color mainColor = null;
        int maxCount = 0;

        for (Map.Entry<Color, Integer> entry : colorCountMap.entrySet()) {
            if (entry.getValue() > maxCount) {
                maxCount = entry.getValue();
                mainColor = entry.getKey();
            }
        }

        return mainColor;
    }
}
